using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using FoundationLib.Ifc.DependencyInjection;

namespace FoundationLib.Ifc.Domain
{
	/// <summary>
	/// Provides functionality for a central message bus
	/// </summary>
	public static class Bus
	{
		/// <summary>
		/// The concrete bus instance used by this singleton
		/// </summary>
		[ThreadStatic]
		private static IMessageBus instance;

		/// <summary>
		/// Initialises the bus using the given concrete bus implementation
		/// </summary>
		/// <param name="bus">The concrete bus implementation</param>
		public static void Initialise(IMessageBus bus)
		{
			if (bus == null)
				throw new ArgumentNullException("bus");
			instance = bus;
		}

		/// <summary>
		/// Clears all registered ad-hoc message handlers. This does not affect handlers 
		/// resolved through dependency injection.
		/// </summary>
		public static void ShutDown()
		{
			if (instance != null)
				instance.Dispose();
		}

		/// <summary>
		/// Sends a message to the bus.
		/// </summary>
		/// <param name="command">The command to send to the bus</param>
		public static void Send<T>(T command) where T : ICommand
		{
			if (instance != null)
				instance.Send(command);
		}

		/// <summary>
		/// Subscribes an ad-hoc message handler with the repository.
		/// </summary>
		/// <remarks>This method may be used to register ad-hoc message handler delegates, 
		/// e.g. for testing purposes. Alternatively, message handlers can be registered 
		/// using dependency injection, that is, by configuring the <see cref="IContainer"/> instance.</remarks>
		/// <typeparam name="T">The type of message</typeparam>
		/// <param name="handler">The message handler</param>
		public static void Subscribe<T>(Action<T> handler) where T : IMessage
		{
			Contract.Requires(handler != null, "A handler action must be specified.");
			if (instance != null)
				instance.Subscribe(handler);
		}

		/// <summary>
		/// Clears all subscriptions made explicitly with this bus
		/// </summary>
		public static void ClearSubscriptions()
		{
			if (instance != null)
				instance.ClearSubscriptions();
		}

		/// <summary>
		/// Publishes a domain event to the bus
		/// </summary>
		/// <param name="domainEvent">The domain event to publish</param>
		public static void Publish<T>(T domainEvent) where T : IEvent
		{
			if (instance != null)
				instance.Publish(domainEvent);
		}

	}
}